from django.shortcuts import render, redirect
# 导包
from django.http import HttpResponse, HttpResponseRedirect, JsonResponse
# 导入类视图
from django.views import View

# from myapp.models import User
import json
from django.core.serializers import serialize
from rest_framework.response import Response
from rest_framework.views import APIView
# 导入加密库
import hashlib
# 导入图片库
# 绘画库
from PIL import ImageDraw
# 字体库
from PIL import ImageFont
# 图片库
from PIL import Image
# 随机库
import random
# 文件流
import io

import requests

# 导入上传文件夹配置
from mydjango.settings import UPLOAD_ROOT
import os

# 导入原生sql模块
from django.db import connection

import jwt

# 导入redis数据库
import redis

# 导入时间模块
import time

# 导入公共目录变量
from mydjango.settings import BASE_DIR

# 导包
from django.db.models import Q, F

# 导入dwebsocket的库
from dwebsocket.decorators import accept_websocket
import uuid

from myapp.models import Cate,User,Pics,Goods,Comment,UserFlow

from myapp.myser import CateSer,UserSer,PicsSer,GoodsSer,CommentSer

#导入钉钉三方登录所需库
import hmac
import base64
from hashlib import sha256
import urllib

# 导入中间件包
from django.utils.deprecation import MiddlewareMixin

#导入redis
import redis

#定义ip地址和端口
host = '127.0.0.1'
port = 6379

#生成链接对象
r = redis.Redis(host=host,port=port)

import pymongo
import jwt

#建立mongo连接对象
mongo_client = pymongo.MongoClient(host='localhost',port=27017)

#导入bson
from bson import json_util as jsonb


#验证用户身份信息是否为管理员
class ValidationAdmin(APIView):
    def get(self,request):
        uid = request.GET.get('uid',None)

        #查询用户信息
        user = User.objects.filter(id=uid).first()

        #判断
        if user and user.type == 1:
            res = {}
            res['code'] = 200
            res['u_type'] = user.type
            res['message'] = '该用户是管理员,可以操作后台'

            return Response(res)
        else:
            res = {}
            res['code'] = 405
            res['u_type'] = user.type
            res['message'] = '用户身份为普通用户,无法操作后台'

            return Response(res)
#添加商品接口
class InsertGoods(APIView):
    def get(self,request):
        #获取前端数据
        name = request.GET.get('name','null')
        desc = request.GET.get('desc','null')
        parms = request.GET.get('parms','null')
        price = request.GET.get('price','null')
        cate_id = request.GET.get('cate_id','null')

        # print(name)
        # print(desc)
        # print(parms)
        # print(price)
        # print(cate_id)

        #排重
        goods = Goods.objects.filter(name=name).first()

        #判断是否存在
        if goods:
            res = {}
            res['code'] = 405
            res['message'] = "该商品已存在"

            return Response(res)
        else:
            goods = Goods(name=name,desc=desc,parms=parms,price=price,cate_id=cate_id)
            goods.save()

            #查询商品id
            goods = Goods.objects.filter(name=name).first()

            # 使用redis存储商品规格数据
            parms = bytes(parms, encoding='utf-8')
            # print(type(parms))
            r.set('parms_json', parms)
            redis_parms = r.get('parms_json').decode('utf-8')
            # print("redis中存储的商品规格数据: ",redis_parms)

            res = {}
            res['code'] = 200
            res['id'] = goods.id
            res['message'] = "商品入库成功"

            return Response(res)


#商品列表页(分页展示接口)
class GoodsList(APIView):
    def get(self,request):
        #当前页
        page = int(request.GET.get('page',1))
        #一页展示多少条商品
        size = int(request.GET.get('size',4))

        #定义从哪个位置开始进行切片
        data_start = (page-1) * size

        #定义切到那个位置
        data_end = page * size

        #查询数据
        goodslist = Goods.objects.all()[data_start:data_end]

        #查询总数量
        count = Goods.objects.count()

        #序列化给前端返回数据
        goods_ser = GoodsSer(goodslist,many=True)

        res = {}
        res['total'] = count
        res['data'] = goods_ser.data

        return Response(res)

#商品详情页接口
class GoodsItem(APIView):
    def get(self,request):
        id = request.GET.get('id','null')

        # print(id)

        goods = Goods.objects.filter(id=id).first()

        if goods:
            goods_ser = GoodsSer(goods,many=False)

            res = {}
            res['code'] = 200
            res['data'] = goods_ser.data

            return Response(res)

#商品标签添加接口
class InsertTags(APIView):
    def get(self,request):
        #接收参数
        id = request.GET.get('id',None)
        #接收标签参数
        tags = request.GET.get('tags',None)

        #分隔转换为列表
        tags = tags.split(',')
        #打印查看结果
        # print(tags)
        # tags = ",".join(tags)
        # tags = ",".join((['&s' % tag for tag in tags])) #通过列表推导式将列表转成字符串
        # print(tags)

        # 建立数据库对象
        db = mongo_client.md
        # 建立表对象
        table = db.mytag

        #排重
        #查询
        res = table.find({"gid":str(id)}).count()
        # print("count:",res)

        if  res > 0:
            return Response({'message':"重复数据"})
        else:
            table.insert({'gid':str(id),'tags':tags})
        return Response({"message":'入库成功'})


class TagMongo(APIView):
    def get(self,request):
        id = request.GET.get('id','0')
        # tags = request.GET.get('tags')
        color = request.GET.get('color', 'null')
        size = request.GET.get('size', 'null')

        # print("id:",id)
        # print('tags:',tags)
        # print("color:", color)
        # print("size:", size)

        goods = Goods.objects.filter(id=id).first()
        title = goods.name

        # 1.创建连接
        conn = pymongo.MongoClient('localhost', 27017)
        # 连接库
        db = conn.tagmongo
        # 连接表
        table = db.test

        #插入数据
        table.insert_one({'title': title, "color": color, 'size': size})

        res = {}
        res['code'] = 200
        res["message"] = "储存成功"

        return Response(res)


#获取商品标签接口
    #继承自View(由于使用的是二进制json)
class GetTags(View):
    def get(self,request):
        # 接收参数
        id = request.GET.get('id', None)

        # 建立数据库对象
        db = mongo_client.md
        # 建立表对象
        table = db.mytag

        #查询数据
        res = table.find_one({'gid':str(id)})

        #返回结果数据
        return HttpResponse(jsonb.dumps(res,ensure_ascii=False))

# 使用redis存储商品标签
class RedisTags(APIView):
    def get(self,request):
        #接收参数
        id = request.GET.get('id',None)
        tags = request.GET.get('tags',None)

        #2020.03.25(个人作业)
        # r.set(id,tags)
        # q = r.get(id).decode('utf-8')
        # print(tags)

        #2020.03.26(个人作业)
        tags = tags.split(",")

        for i in range(len(tags)):
            print(tags[i])
            r.sadd('settags',str(tags[i]))

        myset = r.smembers('settags')
        print("settags: ",myset)
        #
        myset = list(myset)
        mytag = str(myset[0],'utf-8')
        print(mytag)

        #高海航的代码(参考)
        # for i in range(len(tags)):
        #     # print(tags[i])
        #     r.sadd('testset', str(tags[i]))
        # redis_set = r.smembers('testset')
        #
        # print(redis_set)



        res = {}
        res['code'] = 200
        res['message'] = "商品标签存入redis成功"
        # res['tags'] = q
        return Response(res)


class UpdateGoods(APIView):
    def post(self,request):
        #获取前端数据
        id = request.POST.get('id',None)
        name = request.POST.get('name','null')
        desc = request.POST.get('desc','null')
        parms = request.POST.get('parms','null')
        price = request.POST.get('price','null')
        cate_id = request.POST.get('cate_id','null')

        # print(type(price))
        #排重
        goods = Goods.objects.filter(id=id).first()

        #判断是否存在
        if goods:
            goods.name = name
            goods.desc = desc
            goods.parms = parms
            goods.price = int(price)
            goods.cate_id = int(cate_id)

            goods.save()

            res = {}
            res['code'] = 200
            res['id'] = id
            res['message'] = "商品数据修改成功"

            return Response(res)
        else:
            res = {}
            res['code'] = 405
            res['message'] = "商品修改失败"

            return Response(res)


#修改MongoDB中储存的标签接口
class UpdateTags(APIView):
    def get(self,request):
        #接收参数
        id = request.GET.get('id',None)
        #接收标签参数
        tags = request.GET.get('tags',None)

        #分隔转换为列表
        tags = tags.split(',')
        #打印查看结果
        # print(tags)
        # tags = ",".join(tags)
        # tags = ",".join((['&s' % tag for tag in tags])) #通过列表推导式将列表转成字符串
        # print(tags)

        # 建立数据库对象
        db = mongo_client.md
        # 建立表对象
        table = db.mytag

        #排重
        #查询
        res = table.find({"gid":str(id)}).count()
        # print("count:",res)

        if  res > 0:
            db.table.update({'gid':str(id)},{'$set':{'gid':str(id),'tags':tags}})

            return Response({'code':200,'message':"标签修改成功"})
        else:
            # table.insert({'gid':str(id),'tags':tags})
            return Response({'code':405,'message':"标签修改失败"})
        # return Response({"message":'入库成功'})


#统计在线人数
class GetOnLine(APIView):
    def get(self,request):
        #获取客户端IP
        if 'HTTP_X_FORWARDED_FOR' in request.META:
            #取得IP
            ip = request.META.get('HTTP_X_FORWARDED_FOR')
        else:
            #
            ip = request.META.get('REMOTE_ADDR')

        #对用户IP进行存储
        r.sadd('online',ip)

        #设置超时时间
            #参数:    key,    超时时长(单位为秒)
        r.expire('online',30)

        #获取在线人数的数量
        myset = r.smembers('online')

        #返回数据
        return Response({'online':len(myset)})


class GetNum(APIView):
    def get(self,request):
        #查看redis列表内信息数目
        num = r.llen('count_num')
        # print(num)
        # print(type(num))

        #查看
        count = r.llen('count_num')
        # count_list = r.lrange('count_num', 0, r.llen('count_num'))

        res = {}
        res['num'] = num
        res['count'] = count
        # res['count_list'] = count_list

        return Response(res)

class GetGoodsNum(APIView):
    def get(self,request):
        #定义变量
        count_num = request.GET.get('count_num',"null")
        # count_num = 0
        if count_num == 'null':
            #等于零则加一后存储进redis列表
            r.lpush('count_num',1)
            count = r.llen('count_num')
            count_list = r.lrange('count_num',0,r.llen('count_num'))
            # r.delete('count_num')

            res = {}
            res['count'] = count
            res['count_list'] = count_list

            return Response(res)
        elif count_num != "" and count_num >= str(1):
            #不等于零则在原计数基础上加一后存进redis列表
            count_num = int(count_num) + 1

            r.lpush('count_num', count_num)
            count = r.llen('count_num')
            count_list = r.lrange('count_num', 0, r.llen('count_num'))
            # r.delete('count_num')

            res = {}
            res['count'] = count
            res['count_list'] = count_list

            return Response(res)
        # return Response(num)


#反序列化入库(商品评论)
class InsertComment(APIView):
    def post(self,request):
        print(request.data)
        #data = request.data.copy()
        #data['create_time'] = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")

        print(r.get('comment_uid'))

        #获取uid
        comment_uid = request.POST.get('uid','null')
        print(comment_uid)

        #
        if r.get('comment_uid'):
            return Response({'code':403,'message':'您评论的太快了,请休息一下再评论'})

        #初始化参数
        comment = CommentSer(data=request.data)
        #数据校验
        if comment.is_valid():
            #数据入库
            # comment.create(comment.data)
            comment.save()

            #插入评论标记
            r.set('comment_uid','123')
            r.expire('comment_uid',20)

        return Response({'code':200,'message':'恭喜，评论成功'})
# #反序列化入库
# class InsertComment(APIView):
#     def post(self,request):
#         #初始化参数
#             #不接收参数,直接进行初始化
#         comment = CommentSer(data=request.data)
#         print(request.data)
#         #进行数据校验
#         if comment.is_valid():
#             comment.create(comment.data)
#
#         return Response({'code':200,'message':'评论发布成功'})


#评论列表


# 查看用户评论

class UserList(APIView):
    def get(self,request):
        #查询
        user = User.objects.filter()
        #序列化
        user_ser = UserSer(user,many=True)

        return Response(user_ser.data)


class CommentList(APIView):
    def get(self,request):
        #商品if
        id = request.GET.get('id','null')
        # gid = request.GET.get('gid','null')
        #查询
        comment= Comment.objects.filter(gid=int(id))
        # comment = Comment.objects.filter(gid=int(gid))

        #序列化
        comment_ser = CommentSer(comment,many=True)

        return Response(comment_ser.data)


class GetCommentUsername(APIView):
    def get(self,request):
        #获取用户uid
        uid = request.GET.get('uid','null')
        gid = request.GET.get('gid','null')
        #查询
        user = User.objects.filter(id=uid).first()
        comment = Comment.objects.filter(uid=uid).first()

        print("user_uid: ",user.id)
        print("comment_uid: ",comment.uid)
        res = {}
        if int(uid) == user.id == comment.uid:
            res['username'] = user.username
            return Response(res)
        else:
            res['message'] = "未找到评论用户"
            return Response(res)
        # return Response(res)


#将评论存储到MongoDB中
class CommentMongo(APIView):
    def post(self,request):
        print(request.data)
        # 初始化参数
        comment = CommentSer(data=request.data)
        # # 1.创建连接
        conn = pymongo.MongoClient('localhost', 27017)
        # # 连接库
        db = conn.comment_mongo
        # # 连接表
        table = db.comment
        # 数据校验
        if comment.is_valid():
            #查看返回信息
            print(comment.data)
            # 数据存入MongoDB
            #插入数据
            table.insert_one({'content': comment.data['content'], "uid": comment.data['uid'], 'gid': comment.data['gid']})

            #
            res = {}
            res['code'] = 200
            res["message"] = "储存评论信息成功"
            #返回响应数据
            return Response(res)
        else:
            res = {}
            res['code'] = 405
            res['message'] = "储存评论信息失败"

            #返回响应数据
            return Response(res)


#商品评论列表分页(分页展示接口)
class Goods_Comment_List(APIView):
    def get(self,request):
        #当前页
        page = int(request.GET.get('page',1))    #没传递默认是第一页
        #每页有几条评论展示
        size = int(request.GET.get('size',5))    #没传递默认显示五条评论

        #定义从哪里开始切片
        data_start = (page-1) * size    #当前页减一再乘以页数
        #定义切到哪个位置
        data_end = page * size

        #查询数据
        commentlist = Comment.objects.all()[data_start:data_end]
        #查询总数量
        count = Comment.objects.count()

        #序列化
        comment_ser = CommentSer(commentlist,many=True)

        res = {}
        res['comment_total'] = count
        res['comment_data'] = comment_ser.data

        return Response(res)


# 对结果集进行美化
def dictfetchall(cursor):
    # 获取游标描述
    desc = cursor.description

    return [
        dict(zip([col[0] for col in desc], row))
        for row in cursor.fetchall()
    ]


#商品关注接口
    #查询用户关注过的商品列表
class UidFlow(View):
    def get(self,request):
        uid = request.GET.get('uid',None)
        #建立游标对象
        cursor = connection.cursor()
        #执行sql语句
        cursor.execute('select a.id,a.name,a.create_time from goods a left join userflow b on a.id = b.gid where b.uid = %s' %str(uid))
        #获取结果
        result = dictfetchall(cursor)

        #返回结果
        return HttpResponse(json.dumps(result,ensure_ascii=False,indent=4,default=str),content_type='application/json')


# #商品关注数量接口
# class GoodFlow_num(View):
#     def get(self,request):
#         gid = request.GET.get('gid',None)
#         #建立游标对象
#         cursor = connection.cursor()
#         #执行sql
#         cursor.execute('select count(*) from userflow where gid = %s' %str(gid))
#         #获取结果
#         result = dictfetchall(cursor)
#
#         #返回结果
#         return HttpResponse(json.dumps(result,ensure_ascii=False),content_type='application/json')


# 查询商品被哪些用户所关注接口
class GoodFlow_User(View):
    def get(self, request):
        gid = request.GET.get('gid', None)
        # 建立游标对象
        cursor = connection.cursor()
        # 执行sql
        cursor.execute('select a.id,a.username from user a left join userflow b on a.id = b.uid where b.gid = %s' % str(gid))
        # 获取结果
        result = dictfetchall(cursor)

        # 返回结果
        return HttpResponse(json.dumps(result, ensure_ascii=False,indent=4,default=str), content_type='application/json')


# class AddFlow(APIView):
#     def get(self,request):
#         uid = request.GET.get('uid',None)
#         gid = request.GET.get('gid',None)
#
#         userflow = UserFlow.objects.filter(uid=uid,gig=gid).first()
#
#         if userflow:
#             res = {}
#             res['code'] = 405
#             res['message'] = '您已经关注过了,不需要重复关注该商品了'
#
#             return Response(res)
#
#         else:
#             userflow = UserFlow(uid=uid,gid=gid)
#             userflow.save()
#
#             res = {}
#             res['code'] = 200
#             res['message'] = '关注商品成功'
#
#             return Response(res)
#
''''''
#关注商品接口
    #暗含取消关注接口
class GetFlow(APIView):
    def get(self,request):
        id = request.GET.get('id',None)
        uid = request.GET.get('uid',None)
        type = request.GET.get('type',1)

        if int(type) == 1:
            #关注
            userflow = UserFlow(gid = int(id),uid = int(uid))
            try :
                userflow.save()
                message = "关注成功"

                #关注成功后使goods表内flow字段数加一
                goods = Goods.objects.filter(id=int(id)).first()
                goods.flow = goods.flow + 1
                goods.save()

                #将uid与关注数存入redis
                r.zadd("goods_comment",{str(id):str(goods.flow)})
                #遍历展示是否已经存入
                print(r.zrange('goods_comment',0,-1,desc=False,withscores=True))

                return Response({'message': message})

            except Exception as e:
                print(str(e))
                message = "请勿重复关注该商品"

                return Response({'message':message})
                # pass
        elif int(type) == 0:
            #取关
            UserFlow.objects.filter(gid=int(id),uid=int(uid)).delete()

            message = "取关成功"

            # 关注成功后使goods表内flow字段数减一
            goods = Goods.objects.filter(id=int(id)).first()
            if goods.flow != 0:
                goods.flow = goods.flow - 1
                goods.save()

                return Response({"message": message})

            else:
                message = "您还没有关注该商品"

                return Response({"message": message})

        else:
            #批量取关
            ids = request.GET.get('ids',None)
            #进行批量取关
            UserFlow.objects.filter(uid=int(uid)).delete()

            #强转为列表
            id_list= eval(ids)

            for id in id_list:
                userflow = UserFlow(gid = int(id),uid = int(uid))
                userflow.save()

            message = "批量关注成功"

        return Response({"message":message})


#查询关注商品用户名及商品总数
class FlowNum(View):
    def get(self,request):
        gid = request.GET.get('gid',None)
        # 建立游标对象
        cursor = connection.cursor()
        # 执行sql
        cursor.execute('SELECT a.username,c.flow from user a left join userflow b on a.id = b.uid left join goods c on c.id = b.gid where b.gid = %s' % str(gid))
        # 获取结果
        result = dictfetchall(cursor)

        # 返回结果
        return HttpResponse(json.dumps(result, ensure_ascii=False, indent=4, default=str),
                            content_type='application/json')


#工具方法,获取前几名数据
def Get_top_n(num):
    #获取redis中数据
    goods_click= r.zrange('good_rank', 0, -1, desc=True, withscores=True)[:num]

    #正序排序
    # goods_click= r.zrange('good_rank', 0, -1, desc=True, withscores=True)[:num]

    #打印查看是否成功取出
    # print(goods_click)

    #获取MySQL中的数据
    goods = Goods.objects.in_bulk([int(item[0]) for item in goods_click])

    # print(goods)

    #合并操作
    res = []

    for item in goods_click:
        #遍历列表
        #捕获异常
        try:
            res.append({int(item[1]):goods[int(item[0])]})
        except Exception as e:
            pass

    print(res)

    return res


#新的商品参与排名
class GoodsClick(APIView):
    def get(self,request):
        #接受参数
            #商品ID(作为商品名称存在)
        id = request.GET.get('id',None)

        #修改商品点击数
        r.zincrby("good_rank",1,int(id))

        # print(r.zrange('good_rank', 0, -1, desc=True, withscores=True))
        Get_top_n(10)

        #返回
        return Response({"message":'访问加一'})


#商品排行榜数据视图
class GoodRank(APIView):
    def get(self,request):
        #获取排名前数据
        get_res = Get_top_n(10)

        res = []

        #遍历进行序列化
        for dic in get_res:
            for k,v in dic.items():
                #序列化
                data= GoodsSer(v).data
                #将商品点击数附加到序列化商品数据中
                data['clicks'] = k
                res.append(data)

        #返回
        return Response(res)


#商品检索接口
class GoodsSearch(APIView):
    def get(self,request):
        #接收参数
        word = request.GET.get('word',None)
        #检索
            #使用模糊匹配
        goodslist = Goods.objects.filter(Q(name__icontains=word) | Q(desc__icontains=word))

        # goodslist = Goods.objects.filter(Q(parms_icontains=word),Q(name__icontains=word) | Q(desc__icontains=word))
        #序列化
        goods_ser = GoodsSer(goodslist,many=True)

        return Response(goods_ser.data)



